﻿/**************************************************************************
* 文件名称: simpleLog.h
* 文件标识:
* 内容摘要: 简单日志(不带有时间显示，保存日志的功能)模块，包括日志、调试，错误检测等功能
* 相关的宏。关于log信息，不同类型的打印信息会以不同的字符开头，以及在配置了支持彩色的
* SecureCRT上会显示不同的颜色，log的级别说明如下:
开头 信息级别         颜色
[D] 调试信息debug   没有特殊颜色 DEBUG()
[I] 普通信息info    没有特殊颜色 INFO()
[W] 警告信息warn    黄色, 目前暂不支持
[E] 错误信息error   红色 ERROR()
[C] 重要错误信息critical 红色, 目前暂不支持
[F] 致命错误信息fatal 蓝色, 目前暂不支持

    可根据终端打印信息及其颜色判断程序运行的状态。每条打印信息后面会带有文件名、函数名以及
行号，可以快速定位到代码中。而且在程序中使用了统一的错误码，如果出错，会在终端上用醒目颜色打
印出错误信息及错误码的值，根据错误码及打印后面的位置信息可迅速定位问题。每个错误码值表示的含
义可参考头文件std_def.h中对枚举类型 EErrorCode 的定义。
    目前仅支持三种级别的log: DEBUG, INFO, ERROR。
* 其它说明:
* 当前版本: V4.0
* 作   者: 李荣业
* 完成日期: 2015-11-25 19:34:20
* 修改记录1:
*     修改日期:
*     版 本 号:
*     修 改 人:
*     修改内容:
**************************************************************************/

#ifndef SIMPLELOG_H
#define SIMPLELOG_H

// set code language
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif

#include <QDebug>
#include "traverse__VA_ARGS__mocro.h"
#include "CQtLog.h"


#define NONE(format, ...)        ((void)0)

#   define ASSERT_PRINT(e) \
    do{ \
        ((e) ? (void)0 : (void)(printf("\033[1;40;31m [SK_ASSERT]assertion failed: %s ,func %s, line %d \033[0m \r\n", #e, __FUNCTION__, __LINE__))); \
    }while(0)

#define LOCATION_PARAM   " [" __FUNCTION__ "() " __FILE__ ":" STR(__LINE__)"]"

#define QDEBUG(format, ...)     QtLogger->debug(format LOCATION_PARAM, ##__VA_ARGS__)
#define QINFO(format, ...)      QtLogger->info(format LOCATION_PARAM, ##__VA_ARGS__)
#define QWARN(format, ...)      QtLogger->warn(format LOCATION_PARAM, ##__VA_ARGS__)
#define QERROR(format, ...)     QtLogger->error(format LOCATION_PARAM, ##__VA_ARGS__)

#define QPRINT_ONE_VAR(var, type)  #var "={}"
#define QVAR_CONNECT_INFO   ", "
#define QFOR_EACH_VAR(v1, ...)      FOR_EACH(QPRINT_ONE_VAR, "he he", QVAR_CONNECT_INFO, v1, ##__VA_ARGS__)

/**
 * @brief QPRINT_VAR 打印出若干个变量的值以及变量名
 * @param v1, ...: 要打印的若干个变量
 */
#define QPRINT_VAR(v1, ...)         QDEBUG(QFOR_EACH_VAR(v1, ##__VA_ARGS__), v1, ##__VA_ARGS__)
#define QPRINT_VAR_I(v1, ...)       QINFO(QFOR_EACH_VAR(v1, ##__VA_ARGS__), v1, ##__VA_ARGS__)
#define QPRINT_VAR_W(v1, ...)       QWARN("Here warn!! " QFOR_EACH_VAR(v1, ##__VA_ARGS__), v1, ##__VA_ARGS__)
#define QPRINT_VAR_E(v1, ...)       QERROR("Here error!! " QFOR_EACH_VAR(v1, ##__VA_ARGS__), v1, ##__VA_ARGS__)

#define QPRINT_VAR2(str, v1, ...)   QDEBUG(str QFOR_EACH_VAR(v1, ##__VA_ARGS__), v1, ##__VA_ARGS__)
#define QPRINT_VAR2_I(str, v1, ...) QINFO(str QFOR_EACH_VAR(v1, ##__VA_ARGS__), v1, ##__VA_ARGS__)
#define QPRINT_VAR2_W(str, v1, ...) QWARN("Here warn!! " str QFOR_EACH_VAR(v1, ##__VA_ARGS__), v1, ##__VA_ARGS__)
#define QPRINT_VAR2_E(str, v1, ...) QERROR("Here error!! " str QFOR_EACH_VAR(v1, ##__VA_ARGS__), v1, ##__VA_ARGS__)

#define QPRINT_ONCE_D(time, v1, ...)        EXEC_ONCE(time, QPRINT_VAR(v1, ##__VA_ARGS__))
#define QPRINT_ONCE_I(time, v1, ...)        EXEC_ONCE(time, QPRINT_VAR_I(v1, ##__VA_ARGS__))
#define QPRINT_ONCE_W(time, v1, ...)        EXEC_ONCE(time, QPRINT_VAR_W(v1, ##__VA_ARGS__))
#define QPRINT_ONCE_E(time, v1, ...)        EXEC_ONCE(time, QPRINT_VAR_E(v1, ##__VA_ARGS__))

#define QPRINT_ONCE2_D(time, str, v1, ...)  EXEC_ONCE(time, QPRINT_VAR2(str, v1, ##__VA_ARGS__))
#define QPRINT_ONCE2_I(time, str, v1, ...)  EXEC_ONCE(time, QPRINT_VAR2_I(str, v1, ##__VA_ARGS__))
#define QPRINT_ONCE2_W(time, str, v1, ...)  EXEC_ONCE(time, QPRINT_VAR2_W(str, v1, ##__VA_ARGS__))
#define QPRINT_ONCE2_E(time, str, v1, ...)  EXEC_ONCE(time, QPRINT_VAR2_E(str, v1, ##__VA_ARGS__))

/// \brief 周期性打印循环产生的日志 time-打印周期, 浮点数，单位: 秒
#define QDEBUG_ONCE(time, ...)      EXEC_ONCE(time, QDEBUG(__VA_ARGS__))
#define QINFO_ONCE(time, ...)       EXEC_ONCE(time, QINFO(__VA_ARGS__))
#define QWARN_ONCE(time, ...)       EXEC_ONCE(time, QWARN(__VA_ARGS__))
#define QERROR_ONCE(time, ...)      EXEC_ONCE(time, QERROR(__VA_ARGS__))

double __eufy_get_timestamp();
/// \brief 周期性执行某操作 time-周期, 浮点数，单位: 秒
#define EXEC_ONCE(time, EXEC)                                       \
    {                                                               \
        static double __last_time##__LINE__ = 0;                    \
        const double __new_time##__LINE__ = __eufy_get_timestamp(); \
        if (__new_time##__LINE__ - __last_time##__LINE__ > (time))  \
        {                                                           \
            __last_time##__LINE__ = __new_time##__LINE__;           \
            EXEC;                                                   \
        }                                                           \
    }

#define HERE        QDEBUG("Here")
#define HERE_WARN   QWARN("Here warn!!")
#define HERE_ERROR  QERROR("Here error!!")

#ifndef BUILD_TIME
#define BUILD_TIME  __DATE__ " " __TIME__
#endif

/*!
*@brief: 欢迎信息日志。一般在软件刚开始运行时使用
*@param appName: 应用程序名称
*@param coName: 公司名称
*/
#define WELCOME_INFO(appName, coName)  \
    qDebug() << endl << endl << \
    "*********************************************************************************************************************************" << endl << \
    "Welcome to use " << appName << " software of " << coName << " company, Compile time:" BUILD_TIME << endl << \
    "*********************************************************************************************************************************" << endl << endl


#ifdef USE_NEW_CHECK_MACRO
#define CHECK_POINTER(p, ...)           if (nullptr == (p)) { QPRINT_VAR_E((void *)p); __VA_ARGS__; }
#define CHECK_BOOL(b, ...)              if (!(b)) { QPRINT_VAR_E((b)); __VA_ARGS__; }
#define CHECK_RET(ret, ...)             if (0 != (ret)) { QPRINT_VAR_E(ret); __VA_ARGS__; }
#define CHECK_RET2(ret, str, ...)       if (0 != (ret)) { QPRINT_VAR2_E(str, ret); __VA_ARGS__; }

#define CHECK_RET_RETURN_FALSE(ret) CHECK_RET(ret, return false)
#define CHECK_RET_RETURN(ret) CHECK_RET(ret, return ret)
#else
#define CHECK_FAIL_EXEC(ret, ...)          if (!(ret)) { HERE_ERROR; __VA_ARGS__; }
#define CHECK_RET(ret)          if (0 != (ret)) { QPRINT_VAR_E((ret)); }
#define CHECK_RET2(ret, str)    if (0 != (ret)) { QPRINT_VAR2_E((str), (ret)); }
#define CHECK_RET_RETURN_FALSE(ret)    CHECK_RET_RETURN(ret, false)

#define CHECK_RET_RETURN(ret, ...) \
if (0 != (ret)) \
    {   \
        QPRINT_VAR_E((ret)); \
        return __VA_ARGS__; \
    }
#endif

#ifdef UNICODE
#define QStringToTCHAR(x)     (wchar_t*) x.utf16()
#define PQStringToTCHAR(x)    (wchar_t*) x->utf16()
#define TCHARToQString(x)     QString::fromUtf16((const ushort *)(x))
#define TCHARToQStringN(x,y)  QString::fromUtf16((x),(y))
#else
#define QStringToTCHAR(x)     x.local8Bit().constData()
#define PQStringToTCHAR(x)    x->local8Bit().constData()
#define TCHARToQString(x)     QString::fromLocal8Bit((x))
#define TCHARToQStringN(x,y)  QString::fromLocal8Bit((x),(y))
#endif

#endif  // SIMPLECOMMACRO_H
